home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / BitTorrent / Storage.py < prev    next >
Encoding:
Python Source  |  2007-11-12  |  5.0 KB  |  174 lines

  1. # Written by Bram Cohen
  2. # see LICENSE.txt for license information
  3.  
  4. from sha import sha
  5. from bisect import bisect_right
  6.  
  7. class Storage:
  8.     def __init__(self, files, open, exists, getsize):
  9.         # can raise IOError and ValueError
  10.         self.ranges = []
  11.         total = 0l
  12.         so_far = 0l
  13.         for file, length in files:
  14.             if length != 0:
  15.                 self.ranges.append((total, total + length, file))
  16.                 total += length
  17.                 if exists(file):
  18.                     l = getsize(file)
  19.                     if l > length:
  20.                         l = length
  21.                     so_far += l
  22.             elif not exists(file):
  23.                 open(file, 'wb').close()
  24.         self.begins = [i[0] for i in self.ranges]
  25.         self.total_length = total
  26.         self.handles = {}
  27.         self.whandles = {}
  28.         self.tops = {}
  29.         for file, length in files:
  30.             if exists(file):
  31.                 l = getsize(file)
  32.                 if l != length:
  33.                     self.handles[file] = open(file, 'rb+')
  34.                     self.whandles[file] = 1
  35.                     if l > length:
  36.                         self.handles[file].truncate(length)
  37.                 else:
  38.                     self.handles[file] = open(file, 'rb')
  39.                 self.tops[file] = l
  40.             else:
  41.                 self.handles[file] = open(file, 'wb+')
  42.                 self.whandles[file] = 1
  43.  
  44.     def was_preallocated(self, pos, length):
  45.         for file, begin, end in self._intervals(pos, length):
  46.             if self.tops.get(file, 0) < end:
  47.                 return False
  48.         return True
  49.  
  50.     def set_readonly(self):
  51.         # may raise IOError or OSError
  52.         for file in self.whandles.keys():
  53.             old = self.handles[file]
  54.             old.flush()
  55.             old.close()
  56.             self.handles[file] = open(file, 'rb')
  57.  
  58.     def get_total_length(self):
  59.         return self.total_length
  60.  
  61.     def _intervals(self, pos, amount):
  62.         r = []
  63.         stop = pos + amount
  64.         p = bisect_right(self.begins, pos) - 1
  65.         while p < len(self.ranges) and self.ranges[p][0] < stop:
  66.             begin, end, file = self.ranges[p]
  67.             r.append((file, max(pos, begin) - begin, min(end, stop) - begin))
  68.             p += 1
  69.         return r
  70.  
  71.     def files_in_range(self, pos, amount):
  72.         return [file for file, pos, end in self._intervals(pos, amount)]
  73.  
  74.     def read(self, pos, amount):
  75.         r = []
  76.         for file, pos, end in self._intervals(pos, amount):
  77.             h = self.handles[file]
  78.             h.seek(pos)
  79.             r.append(h.read(end - pos))
  80.         return ''.join(r)
  81.  
  82.     def write(self, pos, s):
  83.         # might raise an IOError
  84.         total = 0
  85.         for file, begin, end in self._intervals(pos, len(s)):
  86.             if not self.whandles.has_key(file):
  87.                 self.handles[file].close()
  88.                 self.handles[file] = open(file, 'rb+')
  89.                 self.whandles[file] = 1
  90.             h = self.handles[file]
  91.             h.seek(begin)
  92.             h.write(s[total: total + end - begin])
  93.             total += end - begin
  94.    
  95.     def close(self):
  96.         for h in self.handles.values():
  97.             h.close()
  98.  
  99. def lrange(a, b, c):
  100.     r = []
  101.     while a < b:
  102.         r.append(a)
  103.         a += c
  104.     return r
  105.  
  106. # everything below is for testing
  107.  
  108. from fakeopen import FakeOpen
  109.  
  110. def test_Storage_simple():
  111.     f = FakeOpen()
  112.     m = Storage([('a', 5)], f.open, f.exists, f.getsize)
  113.     assert f.files.keys() == ['a']
  114.     m.write(0, 'abc')
  115.     assert m.read(0, 3) == 'abc'
  116.     m.write(2, 'abc')
  117.     assert m.read(2, 3) == 'abc'
  118.     m.write(1, 'abc')
  119.     assert m.read(0, 5) == 'aabcc'
  120.     
  121. def test_Storage_multiple():
  122.     f = FakeOpen()
  123.     m = Storage([('a', 5), ('2', 4), ('c', 3)], 
  124.         f.open, f.exists, f.getsize)
  125.     x = f.files.keys()
  126.     x.sort()
  127.     assert x == ['2', 'a', 'c']
  128.     m.write(3, 'abc')
  129.     assert m.read(3, 3) == 'abc'
  130.     m.write(5, 'ab')
  131.     assert m.read(4, 3) == 'bab'
  132.     m.write(3, 'pqrstuvw')
  133.     assert m.read(3, 8) == 'pqrstuvw'
  134.     m.write(3, 'abcdef')
  135.     assert m.read(3, 7) == 'abcdefv'
  136.  
  137. def test_Storage_zero():
  138.     f = FakeOpen()
  139.     Storage([('a', 0)], f.open, f.exists, f.getsize)
  140.     assert f.files == {'a': []}
  141.  
  142. def test_resume_zero():
  143.     f = FakeOpen({'a': ''})
  144.     Storage([('a', 0)], f.open, f.exists, f.getsize)
  145.     assert f.files == {'a': []}
  146.  
  147. def test_Storage_with_zero():
  148.     f = FakeOpen()
  149.     m = Storage([('a', 3), ('b', 0), ('c', 3)], 
  150.         f.open, f.exists, f.getsize)
  151.     m.write(2, 'abc')
  152.     assert m.read(2, 3) == 'abc'
  153.     x = f.files.keys()
  154.     x.sort()
  155.     assert x == ['a', 'b', 'c']
  156.     assert len(f.files['a']) == 3
  157.     assert len(f.files['b']) == 0
  158.  
  159. def test_Storage_resume():
  160.     f = FakeOpen({'a': 'abc'})
  161.     m = Storage([('a', 4)], 
  162.         f.open, f.exists, f.getsize)
  163.     assert f.files.keys() == ['a']
  164.     assert m.read(0, 3) == 'abc'
  165.  
  166. def test_Storage_mixed_resume():
  167.     f = FakeOpen({'b': 'abc'})
  168.     m = Storage([('a', 3), ('b', 4)], 
  169.         f.open, f.exists, f.getsize)
  170.     x = f.files.keys()
  171.     x.sort()
  172.     assert x == ['a', 'b']
  173.     assert m.read(3, 3) == 'abc'
  174.